package com.web.web.session;

import com.alibaba.fastjson.JSON;
import com.web.farme.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;

@Slf4j
public class RedisSession implements HttpSession {

    private String redisCacheKey;
    private RedisCache redisCache;
    private boolean isNew;
    private int expireSeconds;
    private ServletContext servletContext;
    private String sessionId;
    private Long createTime;


    public RedisSession(RedisCache redisCache, String redisCacheKey, long createTime, String sessionId, ServletContext servletContext, int expireSeconds, boolean isNew) {
        this.redisCacheKey = redisCacheKey;
        this.redisCache = redisCache;
        this.isNew = isNew;
        this.expireSeconds = expireSeconds;
        this.servletContext = servletContext;
        this.sessionId = sessionId;
        this.createTime = createTime;
    }

    public SessionUser getSessionUser() {
        SessionUser sessionUser = new DefaultSessionUser();
        sessionUser.setRedisCacheAndRedisSessionKey(this.redisCache, this.redisCacheKey);
        return sessionUser;
    }

    public <T> T getSessionUser(Class<T> sessionClass) {
        if (!SessionUser.class.isAssignableFrom(sessionClass)) {
            return null;
        } else {
            try{
                T t = sessionClass.newInstance();
                sessionClass.getMethod("setRedisCacheAndRedisSessionKey", RedisCache.class, String.class).invoke(t, this.redisCache, this.redisCacheKey);
                return t;
            }catch (Exception e){
                return null;
            }
        }
    }

    public void updateExpire() {
        this.redisCache.expire(this.redisCacheKey, this.expireSeconds);
    }

    @Override
    public long getCreationTime() {
        return this.createTime;
    }

    @Override
    public String getId() {
        return this.sessionId;
    }

    @Override
    public long getLastAccessedTime() {
        try {
            return Long.parseLong(this.redisCache.getMap(this.redisCacheKey, "lastAccessTime"));
        } catch (Exception e) {
            return 0L;
        }

    }

    @Override
    public ServletContext getServletContext() {
        return this.servletContext;
    }

    @Override
    public void setMaxInactiveInterval(int i) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int getMaxInactiveInterval() {
        return this.expireSeconds;
    }

    @Override
    public HttpSessionContext getSessionContext() {
        throw new UnsupportedOperationException("Not support yet.");
    }

    @Override
    public Object getAttribute(String s) {
        try {
            return this.redisCache.getMap(this.redisCacheKey, s);
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public Object getValue(String s) {
        return this.getAttribute(s);
    }

    @Override
    public Enumeration<String> getAttributeNames() {
        try {
            return new RedisSession.RedisSessionEnumeration(this.redisCache.getAllMap(this.redisCacheKey).keySet());
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public String[] getValueNames() {
        throw new UnsupportedOperationException("Not support yet.");
    }

    /**
     * 将对象以name名称绑定到会话
     */
    @Override
    public void setAttribute(String s, Object o) {
        try {
            if (o instanceof String) {
                this.redisCache.setMap(this.redisCacheKey, s, (String) o);
            } else {
                this.redisCache.setMap(this.redisCacheKey, s, JSON.toJSONString(o));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void putValue(String s, Object o) {
        this.setAttribute(s, o);
    }

    @Override
    public void removeAttribute(String s) {
        try {
            this.redisCache.deleteMap(this.redisCacheKey, s);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void removeValue(String s) {
        removeAttribute(s);
    }

    @Override
    public void invalidate() {
        this.redisCache.delete(this.redisCacheKey);
    }

    @Override
    public boolean isNew() {
        return this.isNew;
    }


    private static class RedisSessionEnumeration<T> implements Enumeration<T> {
        private final Iterator<T> iter;

        public RedisSessionEnumeration(Set<T> attributeNames) {
            this.iter = attributeNames.iterator();
        }

        public boolean hasMoreElements() {
            return this.iter.hasNext();
        }

        public T nextElement() {
            return this.iter.next();
        }
    }
}
